﻿
using CSharpLibs.Annotations;
using System.Collections;
using System.Collections.Generic;

#pragma warning disable 0169

namespace System
{
	[Builtin, BuiltinImplementation]
	public class String : Object, IComparable, IComparable<String>, IEquatable<String>, ICloneable, IEnumerable<char>, IEnumerable
	{
		[MultiLocationField]
		private char sval;
		
		private int slen;

		public static String Empty;
		private static String[] string_intern;

		////
		//Code to help with builtin string representation

		[BuiltinMethod, BuiltinSemantics("internal_string_compare")]
		private static int InternalStringCompare_DoStrings(String s1, int pos1, String s2, int pos2, int length)
		{ return -1; }

		[BuiltinMethod, BuiltinSemantics("internal_string_formatbuild")]
		private static String FormatInsert(String fms, String[] args)
		{ return null; }

		//Done with helper code
		////

		static String()
		{
			char[] empty = new char[0];
			Empty = new String(empty);

			string_intern = new string[10];
		}

		public String(char[] chars)
			: this(chars, 0, chars.Length)
		{ ;}

		[BuiltinMethod, BuiltinSemantics("string_from_chars_rng")]
		public String(char[] chars, int start, int length)
		{ ;}

		public object Clone()
		{ return this; }

		public static int Compare(String s1, String s2)
		{
			if(s1 == null)
			{
				if(s2 == null)
					return 0;
				else
					return -1;
			}
			else if(s2 == null)
				return 1;
			else
				return String.InternalStringCompare_DoStrings(s1, 0, s2, 0, Math.Max(s1.Length, s2.Length));
		}

		public static int Compare(String s1, int index1, String s2, int index2, int length)
		{
			if(s1 == null)
			{
				if(s2 == null)
					return 0;
				else
					return -1;
			}
			else if(s2 == null)
				return 1;
			else
				return String.InternalStringCompare_DoStrings(s1, index1, s2, index2, length);
		}

		public int CompareTo(object o)
		{
			if(o == null)
				return 1;

			if(!(o is String))
				Environment.Exit(1);
			
			return Compare(this, (String)o);
		}

		public int CompareTo(String str)
		{ return Compare(this, str); }

		public static String Concat(String s1, String s2)
		{
			String[] sa = new String[2];
			sa[0] = s1;
			sa[1] = s2;

			return Concat(sa); 
		}

		public static String Concat(String s1, String s2, String s3)
		{
			String[] sa = new String[3];
			sa[0] = s1;
			sa[1] = s2;
			sa[2] = s3;

			return Concat(sa);
		}

		public static String Concat(String s1, String s2, String s3, String s4)
		{
			String[] sa = new String[4];
			sa[0] = s1;
			sa[1] = s2;
			sa[2] = s3;
			sa[3] = s4;

			return Concat(sa);
		}

		[BuiltinMethod, BuiltinSemantics("concat_string_array")]
		public static String Concat(String[] sa1)
		{ return null; }

		public static String Concat(object o1)
		{
			object[] obs = new object[1];
			obs[0] = o1;

			return String.Concat(obs);
		}

		public static String Concat(object o1, object o2)
		{
			object[] obs = new object[2];
			obs[0] = o1;
			obs[1] = o2;

			return String.Concat(obs);
		}

		public static String Concat(object o1, object o2, object o3)
		{
			object[] obs = new object[3];
			obs[0] = o1;
			obs[1] = o2;
			obs[2] = o3;

			return String.Concat(obs);
		}

		public static String Concat(object[] sa1)
		{
			String[] sa = new String[sa1.Length];
			for(int i = 0; i < sa1.Length; ++i)
				sa[i] = (sa1[i] == null ? String.Empty : ((Object)sa1[i]).ToString());

			return Concat(sa);
		}

		public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
		{
			for(int i = sourceIndex; i < count; ++i)
				destination[destinationIndex + i] = this[i];
		}

		public bool EndsWith(String s)
		{
			if(this.Length < s.Length)
				return false;
			else
			{
				int bpos = this.Length - s.Length;
				for(int i = 0; i < s.Length; ++i)
				{
					if(s[i] != this[bpos + i])
						return false;
				}

				return true;
			}
		}

		public override bool Equals(object o)
		{ return this.CompareTo(o) == 0; }

		public bool Equals(String s)
		{ return Compare(this, s) == 0; }

		public static String Format(String fms, object o1)
		{
			object[] obs = new object[1];
			obs[0] = o1;

			return String.Format(fms, obs); 
		}

		public static String Format(String fms, object o1, object o2)
		{
			object[] obs = new object[2];
			obs[0] = o1;
			obs[1] = o2;

			return String.Format(fms, obs);
		}

		public static String Format(String fms, object o1, object o2, object o3)
		{
			object[] obs = new object[3];
			obs[0] = o1;
			obs[1] = o2;
			obs[2] = o3;

			return String.Format(fms, obs);
		}

		public static String Format(String fms, object[] sa1)
		{
			String[] sa = new String[sa1.Length];
			for(int i = 0; i < sa1.Length; ++i)
				sa[i] = (sa1[i] == null ? String.Empty : ((Object)sa1[i]).ToString());

			return FormatInsert(fms, sa);
		}

		public CharEnumerator GetEnumerator()
		{ return new CharEnumerator(this); }

		[BuiltinMethod, BuiltinSemantics("get_string_hashcode")]
		public override int GetHashCode()
		{ return -1; }

		public int IndexOf(char c)
		{ return this.IndexOf(c, 0); }

		public int IndexOf(String s)
		{ return this.IndexOf(s, 0); }

		public int IndexOf(char c, int pos)
		{
			for(int i = pos; i < this.Length; ++i)
			{
				if(this[i] == c)
					return i;
			}

			return -1;
		}

		[BuiltinMethod, BuiltinSemantics("string_indexof_string")]
		public int IndexOf(String s, int pos)
		{ return -1; }

		public int IndexOfAny(char[] c)
		{ return IndexOfAny(c, 0); }

		public int IndexOfAny(char[] c, int pos)
		{
			for(int i = pos; i < this.Length; ++i)
			{
				for(int j = 0; j < c.Length; ++j)
				{
					if(this[i] != c[j])
						return i;
				}
			}

			return -1;
		}

		private static int InternPosFor(String s)
		{
			int pos = s.GetHashCode() % string_intern.Length;
			if(string_intern[pos] == null || s.Equals(string_intern[pos]))
				return pos;

			int i = (pos + 1) % string_intern.Length;
			while(i != pos)
			{
				if(string_intern[i] == null || s.Equals(string_intern[i]))
					return i;

				i = (i + 1) % string_intern.Length;
			}

			return -1;
		}

		public static String Intern(String s)
		{
			int pos = InternPosFor(s);

			//if the table is full rehash
			if(pos == -1)
			{
				String[] tsa = string_intern;
				string_intern = new String[tsa.Length * 2];

				for(int i = 0; i < tsa.Length; ++i)
				{
					int rpos = InternPosFor(tsa[i]);
					string_intern[rpos] = tsa[i];
				}

				//recompte pos
				pos = InternPosFor(s);
			}

			if(string_intern[pos] == null)
				string_intern[pos] = s;

			return string_intern[pos];
		}

		public static bool IsNullOrEmpty(String value)
		{
			if(value != null)
				return (value.Length == 0);
			return true;
		}

		public int LastIndexOf(char c)
		{ return this.LastIndexOf(c, this.Length - 1); }

		public int LastIndexOf(char c, int pos)
		{
			for(int i = pos; i >= 0; --i)
			{
				if(this[i] == c)
					return i;
			}

			return -1;
		}

		public static bool op_Equality(String a, String b)
		{ return Compare(a, b) == 0; }

		public static bool op_Inequality(String a, String b)
		{ return Compare(a, b) != 0; }

		[BuiltinMethod, BuiltinSemantics("string_replace")]
		public String Replace(String srepl, String swith)
		{ return null; }

		[BuiltinMethod, BuiltinSemantics("string_split")]
		public String[] Split(char[] toks)
		{ return null; }

		public bool StartsWith(String s)
		{
			if(this.Length < s.Length)
				return false;
			else
			{
				for(int i = 0; i < s.Length; ++i)
				{
					if(s[i] != this[i])
						return false;
				}

				return true;
			}
		}

		public String Substring(int start)
		{ return this.Substring(start, this.Length - start); }

		public String Substring(int start, int length)
		{
			char[] chrs = new char[length];
			for(int i = 0; i < length; ++i)
				chrs[i] = this[start + i];

			return new String(chrs);
		}

		public char[] ToCharArray()
		{
			char[] chrs = new char[this.Length];
			for(int i = 0; i < this.Length; ++i)
				chrs[i] = this[i];

			return chrs;
		}

		public String ToLower()
		{
			char[] chrs = new char[this.Length];
			for(int i = 0; i < this.Length; ++i)
				chrs[i] = Char.ToLower(this[i]);

			return new String(chrs);
		}

		public String ToUpper()
		{
			char[] chrs = new char[this.Length];
			for(int i = 0; i < this.Length; ++i)
				chrs[i] = Char.ToUpper(this[i]);

			return new String(chrs);
		}

		[BuiltinMethod, BuiltinSemantics("string_trim")]
		public String Trim()
		{ return null; }

		public override String ToString()
		{ return this; }

		[BuiltinMethod, BuiltinSemantics("get_string_char")]
		public char this[int index]
		{ get { return 'a'; } }

		[BuiltinMethod, BuiltinSemantics("get_string_length")]
		public int Length
		{ get { return -1; } }

		IEnumerator<char> IEnumerable<char>.GetEnumerator()
		{ return this.GetEnumerator(); }

		IEnumerator IEnumerable.GetEnumerator()
		{ return this.GetEnumerator(); }
	}
}

#pragma warning restore 0169
